package com.stupidzhe.vbreview.util;

import com.stupidzhe.vbreview.bean.VBAssResultBean;
import com.stupidzhe.vbreview.bean.ZipResultBean;
import de.innosystec.unrar.Archive;
import de.innosystec.unrar.NativeStorage;
import de.innosystec.unrar.exception.RarException;
import de.innosystec.unrar.rarfile.FileHeader;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class FileUtil {

//    static String FILE_PATH = "/Users/Stupidzhe/IT/vb-review/uploadFile/";

    // Windows环境
    static String FILE_PATH = "C:\\Users\\StupidZhe\\Documents\\vb-review\\uploadFile\\";

    static {
        File testDir = new File(FILE_PATH);
        boolean res = testDir.mkdirs();
        if (!res) {
            System.out.println("创建解压路径失败");
        }
    }


    public static String uploadFile(byte[] bytes, String name, String postfix) {
        String lastName = FILE_PATH + name + "." + postfix;
        try {
            File file = new File(lastName);
            file.createNewFile();
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(bytes);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return name + "." + postfix;
    }

    public static ZipResultBean unzip(byte[] bytes, String name, String postfix) {

        ZipResultBean resultBean = new ZipResultBean();
        try {
            switch (postfix) {
                case "zip": {
                    unzip(bytes, name);
                    break;
                }
                case "rar": {
                    unrar(bytes, name);
                    break;
                }
                default: {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            resultBean.setSuccess(false);
            resultBean.setMsg(e.getMessage());
            resultBean.setName(null);
            return resultBean;

        }
        resultBean.setSuccess(true);
        resultBean.setName(name + "." + postfix);
        return resultBean;
    }


    private static void unrar(byte[] bytes, String name) throws Exception {
        String lastName = FILE_PATH + name + ".rar";
        boolean res;

        // 保存压缩文件到本地
        File file = new File(lastName);
        if (file.exists()) {
            res = file.delete();
            if (!res) {
                throw new Exception("删除原文件失败(1)");
            }
        }
        res = file.createNewFile();
        if (!res) {
            throw new Exception("新建文件错误(1)");
        }

        FileOutputStream fileOutputStream = new FileOutputStream(file);
        fileOutputStream.write(bytes);

        FileOutputStream fileOut = null;
        Archive rarfile = null;

        boolean frmFlag = false;
        boolean vbpFlag = false;
        String vbpLocation = null;
        int dirNum = 0;

        try {
            NativeStorage storage = new NativeStorage(file);
            rarfile = new Archive(storage);
            FileHeader fh = rarfile.nextFileHeader();
            while (fh != null) {

                String entrypath = "";
                if (fh.isUnicode()) {//解決中文乱码
                    entrypath = fh.getFileNameW().trim();
                } else {
                    entrypath = fh.getFileNameString().trim();
                }
                entrypath = entrypath.replaceAll("\\\\", "/");

                File file1 = new File(FILE_PATH + entrypath);

                if (fh.getFileNameString().equals("__MACOSX")) {
                    continue;
                }

                // 如果是文件夹
                if (fh.isDirectory()) {

                    if (!fh.getFileNameString().equals(name + "/")) {
                        throw new Exception("文件夹名称格式出错\n(提示：\"学号-作业名称\")");
                    }
                    if (file1.exists()) {
                        deleteAllFilesOfDir(file1);
                    }
                    res = file1.mkdirs();
                    if (!res) {
                        throw new Exception("创建路径失败(1-1)");
                    }
                    dirNum++;

                } else {
                    // 判断文件夹中是否有.frm.vbp文件
                    if ("frm".equalsIgnoreCase(fh.getFileNameString().split("[.]")[fh.getFileNameString().split("[.]").length - 1])) {
                        frmFlag = true;
                    }
                    if ("vbp".equalsIgnoreCase(fh.getFileNameString().split("[.]")[fh.getFileNameString().split("[.]").length - 1])) {
                        vbpLocation = fh.getFileNameString();
                        vbpFlag = true;
                    }

                    File parent = file1.getParentFile();
                    if (parent != null && !parent.exists()) {
                        res = parent.mkdirs();
                        if (!res) {
                            throw new Exception("创建路径失败(1-2)");
                        }
                    }
                    fileOut = new FileOutputStream(file1);
                    rarfile.extractFile(fh, fileOut);
                    fileOut.close();
                }
                fh = rarfile.nextFileHeader();
            }
            rarfile.close();
            if (dirNum != 1) {
                throw new Exception("文件结构错误");
            }

            if (!vbpFlag || !frmFlag) {
                throw new Exception("查看.frm文件.vbp文件是否存在");
            }
            VBAssResultBean bean = VBAssUtil.assProject(vbpLocation);
            if (!bean.isStatus()) {
                throw new Exception(bean.getResult());
            }

        } catch (Exception e) {
            // 删除所有文件
            if (file.exists()) {
                file.delete();
            }
            File un = new File(FILE_PATH + name);
            if (un.exists()) {
                un.delete();
            }
            throw e;
        } finally {
            if (fileOut != null) {
                try {
                    fileOut.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (rarfile != null) {
                try {
                    rarfile.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void unzip(byte[] bytes, String name) throws Exception {
        String lastName = FILE_PATH + name + ".zip";
        boolean res;
        File file = new File(lastName);
        OutputStream outputStream = null;
        ZipInputStream zipInputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            if (file.exists()) {
                deleteAllFilesOfDir(file);
            }

            res = file.createNewFile();
            if (!res) {
                throw new Exception("新建文件错误(2)");
            }

            boolean frmFlag = false;
            boolean vbpFlag = false;
            String vbpLocation = null;
            int dirNum = 0;

            fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(bytes);
            zipInputStream = new ZipInputStream(new FileInputStream(file));
            ZipEntry zipEntry;
            byte[] buffer = new byte[1024];//缓冲器
            int readLength = 0;//每次读出来的长度
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {

                // 忽略掉
                if (zipEntry.getName().contains("__MACOSX")) {
                    continue;
                }

                //若是zip条目目录，则需创建这个目录
                if (zipEntry.isDirectory()) {

                    if (!zipEntry.getName().equals(name + "/") && !zipEntry.getName().equals(name + "\\\\")) {
                        throw new Exception("文件夹名称格式出错\n(提示：\"学号-作业名称\")");
                    }

                    File dir = new File(FILE_PATH + zipEntry.getName());
                    if (dir.exists()) {
                        deleteAllFilesOfDir(dir);
                    }
                    res = dir.mkdirs();
                    if (!res) {
                        throw new Exception("创建文件失败(2-2)");
                    }
                    dirNum++;
                    //跳出
                    continue;
                }

                //若是文件，则需创建该文件
                File file1 = new File(FILE_PATH + zipEntry.getName());
                // 判断文件夹中是否有.frm.vbp文件
                if ("frm".equalsIgnoreCase(zipEntry.getName().split("[.]")[zipEntry.getName().split("[.]").length - 1])) {
                    frmFlag = true;
                } else if ("vbp".equalsIgnoreCase(zipEntry.getName().split("[.]")[zipEntry.getName().split("[.]").length - 1])) {
                    vbpFlag = true;
                    vbpLocation = file1.getPath();
                }
                if (file1.exists()) {
                    res = file1.delete();
                    if (!res) {
                        throw new Exception("删除原文件失败(2)");
                    }
                }
                res = file1.createNewFile();
                if (!res) {
                    throw new Exception("创建文件失败(2)");
                }

                outputStream = new FileOutputStream(file1);

                while ((readLength = zipInputStream.read(buffer, 0, 1024)) != -1) {
                    outputStream.write(buffer, 0, readLength);
                }
                outputStream.close();
            }    // end while

            if (dirNum != 1) {
                throw new Exception("文件结构错误");
            }

            if (!vbpFlag || !frmFlag) {
                throw new Exception("查看.frm文件.vbp文件是否存在");
            }
            VBAssResultBean bean = VBAssUtil.assProject(vbpLocation);
            if (!bean.isStatus()) {
                throw new Exception(bean.getResult());
            }

        } catch (Exception e) {
            // 删除所有文件
            if (file.exists()) {
                deleteAllFilesOfDir(file);
            }
            File un = new File(FILE_PATH + name);
            if (un.exists()) {
                deleteAllFilesOfDir(un);
            }
            e.printStackTrace();
            throw e;
        } finally {
            if (null != outputStream) {
                outputStream.close();
            }
            if (null != zipInputStream) {
                zipInputStream.close();
            }
            if (null != fileOutputStream) {
                fileOutputStream.close();
            }
        }

    }

    private static void deleteAllFilesOfDir(File path) {
        if (null != path) {
            if (!path.exists())
                return;
            if (path.isFile()) {
                boolean result = path.delete();
                int tryCount = 0;
                while (!result && tryCount++ < 10) {
                    System.gc(); // 回收资源
                    result = path.delete();
                }
            }
            File[] files = path.listFiles();
            if (null != files) {
                for (int i = 0; i < files.length; i++) {
                    deleteAllFilesOfDir(files[i]);
                }
            }
            path.delete();
        }
    }

    public static File getFile(String fileName) {
        return new File(FILE_PATH + fileName);
    }
}
